package logic

import (
	"common/global"
	"common/model"
	"context"
	"fmt"
	"time"
	user "user_server/proto"
)

// RetroactiveSign 处理用户补签请求

func (s *UserServer) RetroactiveSign(ctx context.Context, req *user.RetroactiveSignRequest) (*user.RetroactiveSignResponse, error) {
	userId := req.UserId
	retroDate, err := time.Parse("2006-01-02", req.Date)
	if err != nil {
		return nil, fmt.Errorf("日期格式错误（需2006-01-02）")
	}
	currentTime := time.Now()

	//检查补签日期是否有效，确保不是今天或未来的日期。
	// 1. 检查补签日期有效性
	if retroDate.After(currentTime) || retroDate.Format("2006-01-02") == currentTime.Format("2006-01-02") {
		return &user.RetroactiveSignResponse{Success: false, Message: "不能补签今天或未来日期"}, nil
	}
	if currentTime.Sub(retroDate).Hours()/24 > 7 { // 限制最近7天
		return &user.RetroactiveSignResponse{Success: false, Message: "仅支持补签最近7天"}, nil
	}

	//检查该日期是否已签到，通过Redis进行验证。
	yearMonth := retroDate.Format("200601")
	day := retroDate.Day() - 1
	redisKey := fmt.Sprintf("user:sign:%d:%s", userId, yearMonth)
	isSigned, err := global.Client.GetBit(ctx, redisKey, int64(day)).Result()
	if err != nil {
		return nil, fmt.Errorf("补签检查失败: %v", err)
	}
	if isSigned == 1 {
		return &user.RetroactiveSignResponse{Success: false, Message: "该日期已签到"}, nil
	}

	//开启数据库事务，并设置事务回滚的处理逻辑。
	tx := global.Db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()
	var todayRetroCount int64
	tx.Model(&model.SignRecord{}).
		Where("user_id = ? AND type = 2 AND DATE(created_at) = CURDATE()", userId).
		Count(&todayRetroCount)

	if todayRetroCount >= 3 {
		return &user.RetroactiveSignResponse{Success: false, Message: "今日补签次数已达上限"}, nil
	}
	//检查用户是否有足够的补签卡。
	var o model.User
	if err := tx.Where("id = ?", userId).First(&o).Error; err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("用户不存在: %v", err)
	}
	if o.RetroactiveCards <= 0 {
		tx.Rollback()
		return &user.RetroactiveSignResponse{Success: false, Message: "补签卡不足"}, nil
	}

	//扣除用户的补签卡（事务）。
	if err := o.DeductRetroactiveCard(); err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("扣除补签卡失败: %v", err)
	}

	//将补签记录写入Redis。
	if _, err := global.Client.SetBit(ctx, redisKey, int64(day), 1).Result(); err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("补签记录失败: %v", err)
	}

	//重新计算用户的连续签到天数，并更新用户信息。
	newContinuous := calculateContinuousDays(userId, currentTime)
	if err := o.UpdateSignInfo(newContinuous, currentTime.Format("2006-01-02")); err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("更新连续天数失败: %v", err)
	}

	signRecord := model.SignRecord{
		UserId:        userId,
		SignDate:      retroDate,
		Type:          2,
		IsRetroactive: 1, // 补签
	}
	if err := tx.Create(&signRecord).Error; err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("创建补签记录失败: %v", err)
	}
	//提交数据库事务，确保所有操作成功。
	if err := tx.Commit().Error; err != nil {
		return nil, fmt.Errorf("事务提交失败: %v", err)
	}
	// 新增补签记录

	return &user.RetroactiveSignResponse{
		Success:        true,
		Message:        "补签成功",
		ContinuousDays: int32(newContinuous),
	}, nil
}

// calculateContinuousDays 简化的连续天数计算（实际需查询Redis历史记录）
func calculateContinuousDays(userId int32, currentTime time.Time) int {
	continuous := 0
	date := currentTime

	// 向前追溯
	for i := 0; i < 30; i++ {
		yearMonth := date.Format("200601")
		day := date.Day() - 1
		redisKey := fmt.Sprintf("user:sign:%d:%s", userId, yearMonth)
		isSigned, _ := global.Client.GetBit(context.Background(), redisKey, int64(day)).Result()

		if isSigned == 1 {
			continuous++
			date = date.AddDate(0, 0, -1)
		} else {
			break
		}
	}

	// 向后检查（处理跨月情况）
	date = currentTime.AddDate(0, 0, 1)
	for i := 0; i < 30; i++ {
		yearMonth := date.Format("200601")
		day := date.Day() - 1
		redisKey := fmt.Sprintf("user:sign:%d:%s", userId, yearMonth)
		isSigned, _ := global.Client.GetBit(context.Background(), redisKey, int64(day)).Result()

		if isSigned == 1 {
			continuous++
			date = date.AddDate(0, 0, 1)
		} else {
			break
		}
	}
	return continuous
}
